package com.youbff.task.core.config;

import javax.sql.DataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.batch.support.DatabaseType;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

import com.youbff.task.core.task.ClientClusterTask;
import com.youbff.task.core.task.LeaderClusterTask;

/**
 * 批处理配置
 * @author lixuefeng
 * @email youbff@163.com
 * @time 2018年1月25日 下午5:43:45
 */
@Configuration
@AutoConfigureAfter(MyBatisMapperScannerConfig.class)
public class BatchConfig {

    /**
     * 用来注册Job的容器
     * @author lixuefeng
     * @email youbff@163.com
     * @time 2018年1月25日 下午5:51:21
     * @param dataSource
     * @param transactionManager
     * @return
     * @throws Exception
     */
    @Bean("jobRepository")
    public JobRepository jobRepository(@Qualifier("taskSystem") DataSource dataSource, PlatformTransactionManager transactionManager) throws Exception{
        JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
        jobRepositoryFactoryBean.setDataSource(dataSource);
        jobRepositoryFactoryBean.setTransactionManager(transactionManager);
        jobRepositoryFactoryBean.setDatabaseType(DatabaseType.MYSQL.name());
        return jobRepositoryFactoryBean.getObject();
    }
    
    /**
     * 作业调度器
     * @author lixuefeng
     * @email youbff@163.com
     * @time 2018年1月25日 下午5:55:16
     * @param dataSource
     * @param transactionManager
     * @return
     * @throws Exception
     */
    @Bean("jobLauncher")
    public SimpleJobLauncher jobLauncher(@Qualifier("taskSystem") DataSource dataSource, PlatformTransactionManager transactionManager) throws Exception{
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(this.jobRepository(dataSource, transactionManager));
        return jobLauncher;
    }
    
    /**
     * 它能够协助用户在上下文中追踪job是否可用，也能够在应用上下文收集在其他地方(子上下文)创建的job信息。
     * 自定义的JobRegistry实现常被用于操作job的名称或是其他属性。
     * 框架提供了一个基于map的默认实现，能够从job的名称映射到job的实例
     * @author lixuefeng
     * @email youbff@163.com
     * @time 2018年1月25日 下午6:00:49
     * @return
     */
    @Bean("jobRegistry")
    public MapJobRegistry mapJobRegistry(){
        return new MapJobRegistry();
    }
    
    /**
     * 这是post处理器，能够将job在创建时自动注册进JobRegistry
     * @author lixuefeng
     * @email youbff@163.com
     * @time 2018年1月26日 上午9:57:01
     * @param jobRegistry
     * @return
     */
    @Bean
    public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(@Qualifier("jobRegistry") MapJobRegistry jobRegistry){
        JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
        jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
        return jobRegistryBeanPostProcessor;
    }
    
    @Bean("scheduler")
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        return schedulerFactoryBean;
    }
    
    /**
     * leader cluster 任务
     * @author lixuefeng
     * @email youbff@163.com
     * @time 2018年1月29日 下午2:44:32
     * @param redisUtil
     * @return
     */
    @Bean("leaderClusterTask")
    public LeaderClusterTask leaderClusterTask(){
        LeaderClusterTask leaderTask = new LeaderClusterTask();
        return leaderTask;
    }
    
    /**
     * 执行步骤
     * @author lixuefeng
     * @email youbff@163.com
     * @time 2018年1月29日 下午2:45:34
     * @param stepBuilderFactory
     * @param leaderTask
     * @return
     */
    @Bean("leaderClusterStep")
    public Step leaderStep(StepBuilderFactory stepBuilderFactory,@Qualifier("leaderClusterTask") LeaderClusterTask leaderTask){
        return stepBuilderFactory.get("leaderClusterStep").tasklet(leaderTask).build();
    }
    
    @Bean("leaderClusterJob")
    public Job leaderJob(JobBuilderFactory jobs,@Qualifier("jobRepository") JobRepository jobRepository,@Qualifier("leaderClusterStep") Step leaderStep){
        return jobs.get("leaderClusterJob").incrementer(new RunIdIncrementer()).repository(jobRepository).flow(leaderStep).end().build();
    }
    
    @Bean("clientClusterTask")
    public ClientClusterTask clientClusterTask(){
        ClientClusterTask clientClusterTask = new ClientClusterTask();
        return clientClusterTask;
    }
    
    @Bean("clientClusterStep")
    public Step clientClusterStep(StepBuilderFactory stepBuilderFactory,@Qualifier("clientClusterTask") ClientClusterTask clientClusterTask){
        return stepBuilderFactory.get("clientClusterStep").tasklet(clientClusterTask).build();
    }
    
    @Bean("clientClusterJob")
    public Job clientClusterJob(JobBuilderFactory jobs,@Qualifier("jobRepository") JobRepository jobRepository,@Qualifier("clientClusterStep") Step leaderStep){
        return jobs.get("clientClusterJob").incrementer(new RunIdIncrementer()).repository(jobRepository).flow(leaderStep).end().build();
    }
}
